package com.example.cc.client.refresh;

import com.example.cc.client.manager.FieldMapCache;
import com.example.cc.client.utils.ConfigUtil;
import com.example.cc.common.annotation.MyValue;
import com.example.cc.common.constants.ConfigConstants;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;

@Component
@Slf4j
public class PropertyRefresher implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Resource
    private FieldMapCache fieldMapCache;

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 刷新指定名称的 Bean。
     *
     * @param beanName 要刷新的 Bean 名称
     */
    public void refreshBean(String beanName) {
        if (applicationContext.containsBean(beanName)) {
            log.info("Refreshing bean: {}", beanName);
            // 直接从上下文中获取新的 Bean 实例
            Object newBean = applicationContext.getBean(beanName);
            log.info("Bean refreshed: {}", beanName);
        } else {
            log.warn("Bean not found: {}", beanName);
        }
    }

    /**
     * 刷新所有带有特定注解的 Bean。
     *
     * @param annotationClass 注解类型
     */
    public void refreshBeansAnnotatedWith(Class<? extends Annotation> annotationClass) {
        Map<String, Object> annotatedBeans = applicationContext.getBeansWithAnnotation(annotationClass);
        for (String beanName : annotatedBeans.keySet()) {
            refreshBean(beanName);
        }
    }

    public void refresh(String key, Object value) {
        // 获取所有带有 MyValue 注解的 Bean 的名称，这里为空
        String[] beanNames = applicationContext.getBeanNamesForAnnotation(MyValue.class);
        for (String beanName : beanNames) {
            Object bean = applicationContext.getBean(beanName);
            Field[] fields = bean.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(MyValue.class)) {
                    MyValue myValue = field.getAnnotation(MyValue.class);
                    String originalKey = ConfigUtil.getOriginalKey(myValue.value());

                    if (originalKey.equals(key)) {
                        field.setAccessible(true);
                        try {
                            field.set(bean, value);
                        } catch (IllegalAccessException e) {
                            log.error("Error updating field: {}", e.getMessage());
                        }
                        field.setAccessible(false);
                    }
                }
            }
        }
    }

    public void doRefresh(String key, Object value) {
        Class<?> targetClazz = fieldMapCache.getKeyFieldCache().get(key);
        if (targetClazz != null) {
            Object bean = applicationContext.getBean(targetClazz);
            findAndRefreshField(key, value, targetClazz, bean);
            return;
        }
        String[] beanNames = applicationContext.getBeanDefinitionNames();
        Arrays.stream(beanNames).filter(beanName -> beanName.endsWith(ConfigConstants.CONTROLLER) || beanName.endsWith(ConfigConstants.SERVICE))
                .forEach(beanName -> {
                    Object bean = applicationContext.getBean(beanName);
                    Class<?> clazz = bean.getClass();
                    if (!clazz.getName().startsWith(ConfigConstants.DEFAULT_PACKAGE_NAME)) {
                        return;
                    }
                    findAndRefreshField(key, value, clazz, bean);
                });
    }

    private static void findAndRefreshField(String key, Object value, Class<?> clazz, Object bean) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(MyValue.class)) {
                MyValue myValue = field.getAnnotation(MyValue.class);
                String originalKey = ConfigUtil.getOriginalKey(myValue.value());

                if (originalKey.equals(key)) {
                    field.setAccessible(true);
                    try {
                        field.set(bean, ConfigUtil.convertValue(value, field.getType()));
                    } catch (IllegalAccessException e) {
                        log.error("update field error : {}", e.getMessage());
                    } finally {
                        field.setAccessible(false);
                    }
                }
            }
        }
    }


    public static void main(String[] args) {
        PropertyRefresher refresher = new PropertyRefresher();
        refresher.refreshBeansAnnotatedWith(Configurable.class);
    }
}
